///
/// AEye, Inc. ("COMPANY") CONFIDENTIAL
/// Unpublished Copyright (c) 2013-2023 AEye, Inc., All Rights Reserved.
///
/// NOTICE:  All information contained herein is, and remains the property of COMPANY.
/// The intellectual and technical concepts contained herein are proprietary to COMPANY and
/// may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or copyright law.
/// Dissemination of this information or reproduction of this material is strictly forbidden unless
/// prior written permission is obtained from COMPANY.
/// Access to the source code contained herein is hereby forbidden to anyone except current COMPANY employees, managers,
/// or contractors who have executed Confidentiality and Non-disclosure agreements explicitly covering such access.
///
/// The copyright notice above does not evidence any actual or intended publication or disclosure of this source code,
/// which includes information that is confidential and/or proprietary, and is a trade secret, of  COMPANY.
/// ANY REPRODUCTION, MODIFICATION, DISTRIBUTION, PUBLIC PERFORMANCE, OR PUBLIC DISPLAY OF OR THROUGH USE OF THIS
/// SOURCE CODE WITHOUT THE EXPRESS WRITTEN CONSENT OF COMPANY IS STRICTLY PROHIBITED, AND IN VIOLATION OF APPLICABLE
/// LAWS AND INTERNATIONAL TREATIES. THE RECEIPT OR POSSESSION OF THIS SOURCE CODE AND/OR RELATED INFORMATION DOES NOT
/// CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE, DISCLOSE, OR DISTRIBUTE ITS CONTENTS, OR TO MANUFACTURE, USE, OR SELL
/// ANYTHING THAT IT  MAY DESCRIBE, IN WHOLE OR IN PART.
///

#ifndef DIAGNOSTICAPI_HPP
#define DIAGNOSTICAPI_HPP

#include <cstdint>
#ifdef _MSC_VER
#define ATTRIBUTE_PACKED
#else
#define ATTRIBUTE_PACKED __attribute__((__packed__))
#endif

/// @cond UNSUPPORTED

/// @file DiagnosticAPI.hpp

namespace aeye {
  /// @struct aeye::IrpsGlobalStatus
  /// @brief Power management unit Global Status
  typedef struct {
    unsigned char syncState;            ///< 0 = use local clock, 1 = locking to sync clock, 2 = use sync clock, 3 = locking to lock clock
    bool          syncInRange;          ///< Input Clock is within required frequency range
    bool          vccUvFault;           ///< True if Vcc is under voltage
    bool          vdrvUvFault;          ///< True if Global Vdrv Chip FET driver is under voltage
    uint8_t       roAlertSignals;       ///< Bit 4 - if 1 => LDO Linear Regulator Alert <br>
                                        ///< Bit 3 - if 1 => Switcher D Alert <br>
                                        ///< Bit 2 - if 1 => Switcher C Alert <br>
                                        ///< Bit 1 - if 1 => Switcher B Alert <br>
                                        ///< Bit 0 - if 1 => SwitcherA Alert <br>
  } ATTRIBUTE_PACKED IrpsGlobalStatus;

  /// @struct aeye::IrpsGlobalPacket
  /// @brief Power management unit Global Status Pocket
  typedef struct {
    IrpsGlobalStatus     irpsGlobStat;  ///< Global Status <br>
                                        ///< Bit 9:8 - Sync_State - 0 = use local clock, 1 = locking to sync clock, 2 = use sync clock, 3 = locking to lock clock <br>
                                        ///< Bit 7 - Sync_In_Range - if 1 => input clock is within required frequency range <br>
                                        ///< Bit 6 - Vcc_UV_Fault - if 1 => Vcc is under voltage <br>
                                        ///< Bit 5 - VDrv_UV_Fault - if 1 => VDrv is under voltage <br>
                                        ///< Bit 4 - if 1 => LDO Alert <br>
                                        ///< Bit 3 - if 1 => Switcher D Alert <br>
                                        ///< Bit 2 - if 1 => Switcher C Alert <br>
                                        ///< Bit 1 - if 1 => Switcher B Alert <br>
                                        ///< Bit 1 - if 1 => Switcher A Alert <br>
    uint32_t             globVcc;   ///< Chip Vcc power supply (V) - Please type cast to float32_t if the struct is used directly
    uint32_t             globVdrv;  ///< Chip FET drive voltage (V) - Please type cast to float32_t if the struct is used directly
    uint32_t             globTotalInputPwr;   ///< Total power consumed by chip from up-stream supply (W) - Please type cast to float32_t if the struct is used directly
    uint32_t             pktCt;     ///< Number of valid packet received for a given device
  } ATTRIBUTE_PACKED IrpsGlobalPacket;

  /// @struct aeye::IrpsChannelStatus1
  /// @brief Power Management Unit Channel Status 1
  typedef struct {
    uint8_t  channelState;     ///< Bit 4 -  if true => Channel 4 Alarm <br>
                               ///< Bit 3 -  if true => Channel 3 Alarm <br>
                               ///< Bit 2 -  if true => Channel 2 Alarm <br>
                               ///< Bit 1 -  if true => Channel 1 Alarm <br>
                               ///< Bit 0 -  if true => Channel 0 Alarm <br>
      uint8_t  statusCml;     ///< Bit 5 - Packet Error Check Failed <br>
                            ///< Bit 4 - Memory Fault Detected <br>
                            ///< Bit 3 - Processor Fault Detected <br>
                            ///< Bit 1 - Other communication fault<br>
                            ///< Bit 0 - Other Memory Or Logic Fault has occurred. <br>
    uint16_t statusWord;    ///< Bit 7 - Device Not Responding Paule <br>
                            ///< Bit 6 - Not Providing Power Fault <br>
                            ///< Bit 5 - Output over voltage fault <br>
                            ///< Bit 4 - Output over current fault <br>
                            ///< Bit 3 - Input under voltage fault <br>
                            ///< Bit 2 - Temperature fault or warning <br>
  } ATTRIBUTE_PACKED IrpsChannelStatus1;

  /// @struct aeye::IrpsChannelStatus2
  /// @brief Power Management Unit Channel Status 2
  typedef struct {
    uint8_t statusTemp;      ///< Temperature Status <br>
                             ///< bit 7 - OT_FAULT (Overtemperature Fault) <br>
                             ///< Bit 6 OT_WARNING (Overtemperature Warning) <br>
                             ///< Bit 5 UT_WARNING (Undertemperature Warning) <br>
                             ///< Bit 4 UT_FAULT (Undertemperature Fault) <br>
    uint8_t statusInput;    ///< Power input Status <br>
                            ///< Bit 7 VIN_OV_FAULT (Input Overvoltage Fault) <br>
                            ///< Bit 6 VIN_OV_WARNING (Input Overvoltage Warning) <br>
                            ///< Bit 5 VIN_UV_WARNING (Input Undervoltage Warning) <br>
                            ///< Bit 4 VIN_UV_FAULT (Input Undervoltage Fault) <br>
                            ///< Bit 3 Unit Off For Insufficient Input Voltage <br>
                            ///< Bit 2 IIN_OC_FAULT (Input Overcurrent Fault) <br>
                            ///< Bit 1 IIN_OC_WARNING (Input Overcurrent Warning) <br>
                            ///< Bit 0 PIN_OP_WARNING (Input Overpower Warning) <br>
     uint8_t statusIout;     ///< Current output status <br>
                            ///< Bit 7 IOUT_OC_FAULT (Output Overcurrent Fault) <br>
                            ///< Bit 6 IOUT_OC_LV_FAULT (Output Overcurrent And Low Voltage Fault) <br>
                            ///< Bit 5 IOUT_OC_WARNING (Output Overcurrent Warning) <br>
                            ///< Bit 4 IOUT_UC_FAULT (Output Undercurrent Fault) <br>
                            ///< Bit 3 Current Share Fault <br>
                            ///< Bit 2 In Power Limiting Mode <br>
                            ///< Bit 1 POUT_OP_FAULT (Output Overpower Fault) <br>
                            ///< Bit 0 POUT_OP_WARNING (Output Overpower Warning) <br>

    uint8_t statusVout;     ///< Output Voltage Status <br>
                            ///< Bit 7 VOUT_OV_FAULT (Output Overvoltage Fault)<br>
                            ///< Bit 6 VOUT_OV_WARNING (Output Overvoltage Warning)<br>
                            ///< Bit 5 VOUT_UV_WARNING (Output Undervoltage Warning)<br>
                            ///< Bit 4 VOUT_UV_FAULT (Output Undervoltage Fault)<br>
                            ///< Bit 3 VOUT_MAX Warning<br>
                            ///< Bit 2 TON_MAX_FAULT<br>
                            ///< Bit 1 TOFF_MAX_WARNING<br>
                            ///< Bit 0 VOUT Tracking Error<br>

  } ATTRIBUTE_PACKED IrpsChannelStatus2;


  /// @struct aeye::IrpsPerChannelPacket
  /// @brief Power Management Unit Channel Packet Structure
  typedef struct {
    IrpsChannelStatus1   irpsChannelStatus1;     ///< Power Management Unit Channel Status 1
    IrpsChannelStatus2   irpsChannelStatus2;    ///< Power Management Unit Channel Status 2
    uint32_t             chVin;         ///< Channel Input Voltage (V) - Please type cast to float32_t if the struct is used directly
    uint32_t             chIin;         ///< Channel Current Input (A) - Please type cast to float32_t if the struct is used directly
    uint32_t             chPin;         ///< Channel Power Input (W) - Please type cast to float32_t if the struct is used directly
    uint32_t             chVout;        ///< Channel Voltage Output (V) - Please type cast to float32_t if the struct is used directly
    uint32_t             chIout;        ///< Channel Current Output (A) - Please type cast to float32_t if the struct is used directly
    uint32_t             chPout;        ///< Channel Power Output (W) - Please type cast to float32_t if the struct is used directly
    uint32_t             chTemp;        ///< Channel Temperature (degree C) - Please type cast to float32_t if the struct is used directly
    uint32_t             chVoutPeak;    ///< Channel Output Voltage Peak (V) - Please type cast to float32_t if the struct is used directly
    uint32_t             chIoutPeak;    ///< Channel Output Current Peak (A) - Please type cast to float32_t if the struct is used directly
    uint32_t             chTempPeak;    ///< Channel Temperature Peak (degree C) - Please type cast to float32_t if the struct is used directly
    uint32_t             pktCt;         ///< Channel Packet Count
  } ATTRIBUTE_PACKED IrpsPerChannelPacket;

   /// @struct aeye::IrpsDevPacket
   /// @brief Power Management Unit Device Packet.  There is a total of 5 channels per device
  typedef struct {
    IrpsGlobalPacket     irpsGlobPkt;       ///< Power Managment Unit Global Packet
    IrpsPerChannelPacket irpsPerChPkt0;     ///< Power Management Unit Channel 0 Packet
    IrpsPerChannelPacket irpsPerChPkt1;     ///< Power Management Unit Channel 1 Packet
    IrpsPerChannelPacket irpsPerChPkt2;     ///< Power Management Unit Channel 2 Packet
    IrpsPerChannelPacket irpsPerChPkt3;     ///< Power Management Unit Channel 3 Packet
    IrpsPerChannelPacket irpsPerChPkt4;     ///< Power Management Unit Channel 4 Packet
  } ATTRIBUTE_PACKED IrpsDevPacket;

  /// @struct aeye::PacketDiagnosticBody
  /// @breif Board Level Diagnostic Packet.  There are 2 power management unit per board
  typedef struct {
    uint64_t      sensorId;             ///< sensor ID: [63:48] Unit number, [47:0] MAC address
    uint32_t      telemRev;             ///< Telemetry Revision
    float         brdTempCels;          ///< board Temperature
    float         lsrTempCels;          ///< Laser Temperature
    float         scanheadTempCels;     ///< Scanhead Temperature
    float         scanheadRh;           ///< Scanhead Relative Humidity
    float         scanWindowTempCels;   ///< Scanhead Window Temperature
    float         scanWindowRh;         ///< Scanhead Window Relative Humidity
    float         brdTempNearAdcCels;   ///< board Temperature near ADC
    float         adcTempCels;          ///< ADC Temperature
    float         fpgaDieTemp;
    uint8_t       fanControlReqRpm;
    uint8_t       fanControlTachRpm;
    uint8_t       fanControlReqSens;
    float         laserPower;
    bool          laserActive;
    bool          heaterActive;
    bool          eyeSafetyInterlocksTriggered;
    uint32_t      scanSessionCnt;       ///< Lifetime Unit Lasing Events, i.e. number of times scanning activated
    uint32_t      scannerRunTime;       ///< Liftetime Scanner Run time, i.e. amount of time for active scanning
    uint32_t      unitPowerUpCnt;       ///< Lifetime Unit Power Up Events, i.e. number of times powered on
    uint32_t      unitRunTime;          ///< Lifetime Unit Run Time, i.e. amount of time unit is actively powered on in seconds
    IrpsDevPacket irpsDev0Packet;       ///< power Managament Unit Device 0 Packet
    IrpsDevPacket irpsDev1Packet;       ///< power Managament Unit Device 1 Packet
  } ATTRIBUTE_PACKED PacketDiagnosticBody;

  /// @struct DiagnosticData
  /// @brief Board Level Diagnostic
  struct DiagnosticData {
    uint64_t sensorId;                         ///< sensor ID: [63:48] Unit number, [47:0] MAC address
    uint32_t telemRev;                         ///< telemetry Revision
    float brdTempCels;                         ///< board Temperature
    float lsrTempCels;                         ///< Laser Temperature
    float scanheadTempCels;                    ///< Scanhead Temperature
    float scanheadRh;                          ///< Scanhead Relative Humidity
    float scanWindowTempCels;                  ///< Scanhead Window Temperature
    float scanWindowRh;                        ///< Scanhead Window Relative Humidity
    float brdTempNearAdcCels;                  ///< board Temperature near ADC
    float adcTempCels;                         ///< ADC Temperature
    float fpgaDieTemp;
    uint8_t fanControlReqRpm;
    uint8_t fanControlTachRpm;
    uint8_t fanControlReqSens;
    float laserPower;
    bool laserActive;
    bool heaterActive;
    bool eyeSafetyInterlocksTriggered;
    uint32_t scanSessionCnt;                   ///< Lifetime Unit Lasing Events, i.e. number of times scanning activated
    uint32_t scannerRunTime;                   ///< Liftetime Scanner Run time, i.e. amount of time for active scanning in seconds
    uint32_t unitPowerUpCnt;                   ///< Lifetime Unit Power Up Events, i.e. number of times powered on
    uint32_t unitRunTime;                      ///< Lifetime Unit Run Time, i.e. amount of time unit is actively powered on in seconds
    aeye::IrpsDevPacket irpsDev0Packet{};      ///< power Mangament Unit Device 0 Packet
    aeye::IrpsDevPacket irpsDev1Packet{};      ///< power Mangament Unit Device 1 Packet

    /// @brief Initialize diagnostic data object
    /// @param sensorId -  Sensor ID
    /// @param telemRev - Telemetry Revision
    /// @param brdTempCels - Board Temperature
    /// @param lsrTempCels - Laser Temperature
    /// @param scanheadTempCels - Scanhead Temperature
    /// @param scanheadRh - Scanhead Relative Humidity
    /// @param scanWindowTempCels - Scanhead Window Temperature
    /// @param scanWindowRh -  Scanhead Window Relative Humidity
    /// @param brdTempNearAdcCels - Board Temperature near ADC
    /// @param adcTempCels - ADC Temperature
    /// @param irpsDev0Packet{} -  Power Managament Unit Device 0 Packet
    /// @param irpsDev1Packet{} -  Power Managament Unit Device 1 Packet

      DiagnosticData(uint64_t sensorId, uint32_t telemRev, float brdTempCels, float lsrTempCels, float scanheadTempCels,
                   float scanheadRh, float scanWindowTempCels, float scanWindowRh, float brdTempNearAdcCels, float adcTempCels,
                     float fpgaDieTemp, uint8_t fanControlReqRpm, uint8_t fanControlTachRpm, uint8_t fanControlReqSens,
                     float laserPower, bool laserActive, bool heaterActive, bool eyeSafetyInterlocksTriggered,
                   uint32_t scanSessionCnt, uint32_t scannerRunTime, uint32_t unitPowerUpEvents, uint32_t unitRunTime,
                   IrpsDevPacket irpsDev0Packet, IrpsDevPacket irpsDev1Packet){
      this->sensorId = sensorId;
      this->telemRev = telemRev;
      this->brdTempCels = brdTempCels;
      this->lsrTempCels = lsrTempCels;
      this->scanheadTempCels = scanheadTempCels;
      this->scanheadRh = scanheadRh;
      this->scanWindowTempCels = scanWindowTempCels;
      this->scanWindowRh = scanWindowRh;
      this->brdTempNearAdcCels = brdTempNearAdcCels;
      this->adcTempCels = adcTempCels;
      this->fpgaDieTemp = fpgaDieTemp;
      this->fanControlReqRpm = fanControlReqRpm;
      this->fanControlTachRpm = fanControlTachRpm;
      this->fanControlReqSens = fanControlReqSens;
      this->laserPower = laserPower;
      this->laserActive = laserActive;
      this->heaterActive = heaterActive;
      this->eyeSafetyInterlocksTriggered = eyeSafetyInterlocksTriggered;
      this->scanSessionCnt = scanSessionCnt;
      this->scannerRunTime = scannerRunTime;
      this->unitPowerUpCnt = unitPowerUpEvents;
      this->unitRunTime = unitRunTime;
      this->irpsDev0Packet = irpsDev0Packet;
      this->irpsDev1Packet = irpsDev1Packet;
    }
    /// @brief Initialize diagnostic data object
    explicit DiagnosticData(PacketDiagnosticBody in)
      : sensorId(in.sensorId)
      , telemRev(in.telemRev)
      , brdTempCels(in.brdTempCels)
      , lsrTempCels(in.lsrTempCels)
      , scanheadTempCels(in.scanheadTempCels)
      , scanheadRh(in.scanheadRh)
      , scanWindowTempCels(in.scanWindowTempCels)
      , scanWindowRh(in.scanWindowRh)
      , brdTempNearAdcCels(in.brdTempNearAdcCels)
      , adcTempCels(in.adcTempCels)
      , fpgaDieTemp(in.fpgaDieTemp)
      , fanControlReqRpm(in.fanControlReqRpm)
      , fanControlTachRpm(in.fanControlTachRpm)
      , fanControlReqSens(in.fanControlReqSens)
      , laserPower(in.laserPower)
      , laserActive(in.laserActive)
      , heaterActive(in.heaterActive)
      , eyeSafetyInterlocksTriggered(in.eyeSafetyInterlocksTriggered)
      , scanSessionCnt(in.scanSessionCnt)
      , scannerRunTime(in.scannerRunTime)
      , unitPowerUpCnt(in.unitPowerUpCnt)
      , unitRunTime(in.unitRunTime)
      , irpsDev0Packet(in.irpsDev0Packet)
      , irpsDev1Packet(in.irpsDev1Packet)
    {}
    /// @brief Initialize diagnostic data object
    DiagnosticData(){
      this->sensorId = 0;
      this->telemRev = 0;
      this->brdTempCels = 0;
      this->lsrTempCels = 0;
      this->scanheadTempCels = 0;
      this->scanheadRh = 0;
      this->scanWindowTempCels = 0;
      this->scanWindowRh = 0;
      this->brdTempNearAdcCels = 0;
      this->adcTempCels = 0;
      this->adcTempCels = 0;
      this->fpgaDieTemp = 0;
      this->fanControlReqRpm = 0;
      this->fanControlTachRpm = 0;
      this->fanControlReqSens = 0;
      this->laserPower = 0;
      this->laserActive = 0;
      this->heaterActive = 0;
      this->eyeSafetyInterlocksTriggered = 0;
      this->scanSessionCnt = 0;
      this->scannerRunTime = 0;
      this->unitPowerUpCnt = 0;
      this->unitRunTime = 0;
      this->irpsDev0Packet = {};
      this->irpsDev1Packet = {};
    }

  };

}

/// @endcond

#endif //DIAGNOSTICAPI_HPP
